package controller

import (
	"MsSgServer/constant"
	"MsSgServer/db"
	"MsSgServer/net"
	"MsSgServer/server/login/model"
	"MsSgServer/server/login/proto"
	"MsSgServer/server/models"
	"MsSgServer/utils"
	"github.com/mitchellh/mapstructure"
	"log"
	"time"
)

var DefaultAccount = &Account{}

type Account struct {
}

func (a *Account) Router(r *net.Router) {
	g := r.Group("account")
	g.AddRouter("login", a.login)
}

func (a *Account) login(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
	/** 登陆逻辑
	1. 从前端获取 用户名、密码、硬件id
	2. 根据用户名 查询 user 表 得到数据
	3. 进行密码比对， 如果密码正确 登陆成功
	4. 保存用户登陆记录
	5. 保存用户的最后一次登陆信息
	6. 客户端需要一个session jwt 生成一个加密字符串算法
	7. 客户端 再发起需要用户登陆的行为时 判断用户是否合法
	*/
	// 1. 从前端获取 用户名、密码、硬件id
	loginReq := &proto.LoginReq{}
	loginRes := &proto.LoginRsp{}
	// 采用 map structure 将前段传递过来的 req.Body.Msg 转换为 loginReq
	mapstructure.Decode(req.Body.Msg, loginReq)
	// 	2. 根据用户名 查询 user 表 得到数据
	user := &models.User{}
	ok, err := db.Engine.Table(user).Where("username=?", loginReq.Username).Get(user)
	if err != nil {
		log.Println("用户表查询出错！")
		return
	}

	if !ok {
		// 没有查出来数据
		rsp.Body.Code = constant.UserNotExist
		return
	}
	// 若可以根据用户名查出来数据
	// 3. 进行密码比对， 如果密码正确 登陆成功
	// 对传递过来的密码 用 加密盐 进行加密
	pwd := utils.Password(loginReq.Password, user.Passcode)
	// 与数据库已经加密过的密码进行比对
	if pwd != user.Passwd {
		// 密码错误则返回 该返回码
		rsp.Body.Code = constant.PwdIncorrect
		return
	}
	// 根据用户的 Uid 生成 token
	// Jwt A.B.C  三部分 A 定义加密算法 B 定义放入的数据 C部分 根据秘钥 +A 和 B 生成加密字符串
	token, err := utils.Award(user.UId)
	if err != nil {
		log.Println("生成Token出现错误！", err)
		panic(err)
	}
	// 验证完毕 将 填写返回信息
	rsp.Body.Code = constant.OK
	loginRes.UId = user.UId
	loginRes.Username = user.Username
	loginRes.Session = token
	loginRes.Password = ""
	rsp.Body.Msg = loginRes

	// 4. 保存用户登陆记录
	ul := &model.LoginHistory{
		UId: user.UId, CTime: time.Now(), Ip: loginReq.Ip,
		Hardware: loginReq.Hardware, State: model.Login,
	}
	db.Engine.Table(ul).Insert(ul)
	// 5. 保存用户的最后一次登陆状态记录
	ll := &model.LoginLast{}
	ok, _ = db.Engine.Table(ll).Where("uid=?", user.UId).Get(ll)
	if ok {
		// 有数据更新
		//有数据 更新
		ll.IsLogout = 0
		ll.Ip = loginReq.Ip
		ll.LoginTime = time.Now()
		ll.Session = token
		ll.Hardware = loginReq.Hardware
		db.Engine.Table(ll).Update(ll)
	} else {
		ll.IsLogout = 0
		ll.Ip = loginReq.Ip
		ll.LoginTime = time.Now()
		ll.Session = token
		ll.Hardware = loginReq.Hardware
		ll.UId = user.UId
		_, err := db.Engine.Table(ll).Insert(ll)
		if err != nil {
			log.Println(err)
		}
	}

	// 缓存一下 此用户和当前 ws 链接
	net.Mgr.UserLogin(req.Conn, user.UId, token)
	// 6. 客户端需要一个session jwt 生成一个加密字符串算法
	// 7. 客户端 再发起需要用户登陆的行为时 判断用户是否合法
}
